﻿using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WCAD.Kean
{
    public class SelectDynamicBlocks
    {
        [CommandMethod("SDB")]
        static public void SDB()
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            var ed = doc.Editor;
            var pso =new PromptStringOptions("\nName of dynamic block to search for");
            pso.AllowSpaces = true;
            var pr = ed.GetString(pso);
            if (pr.Status != PromptStatus.OK)
                return;
            string blkName = pr.StringResult;
            List<string> blkNames = new List<string>();
            blkNames.Add(blkName);
            var tr = doc.TransactionManager.StartTransaction();
            using (tr)
            {
                var bt =(BlockTable)tr.GetObject(doc.Database.BlockTableId,OpenMode.ForRead);
                // Start by getting access to our block, if it exists
                if (!bt.Has(blkName))
                {
                    ed.WriteMessage("\nCannot find block called \"{0}\".", blkName);
                    return;
                }
                // Get the anonymous block names
                var btr =(BlockTableRecord)tr.GetObject(bt[blkName], OpenMode.ForRead);
                if (!btr.IsDynamicBlock)
                {
                    ed.WriteMessage("\nCannot find a dynamic block called \"{0}\".", blkName);
                    return;
                }
                // Get the anonymous blocks and add them to our list
                var anonBlks = btr.GetAnonymousBlockIds();
                foreach (ObjectId bid in anonBlks)
                {
                    var btr2 =(BlockTableRecord)tr.GetObject(bid, OpenMode.ForRead);
                    blkNames.Add(btr2.Name);
                }
                tr.Commit();
            }
            // Build a conditional filter list so that only
            // entities with the specified properties are
            // selected
            SelectionFilter sf =new SelectionFilter(CreateFilterListForBlocks(blkNames));
            PromptSelectionResult psr = ed.SelectAll(sf);
            ed.WriteMessage("\nFound {0} entit{1}.",psr.Value.Count,(psr.Value.Count == 1 ? "y" : "ies"));
        }
        private static TypedValue[] CreateFilterListForBlocks(List<string> blkNames)
        {
            // If we don't have any block names, return null
            if (blkNames.Count == 0)
                return null;
            // If we only have one, return an array of a single value
            if (blkNames.Count == 1)
                return new TypedValue[] {new TypedValue((int)DxfCode.BlockName,blkNames[0])
        };
            // We have more than one block names to search for...
            // Create a list big enough for our block names plus
            // the containing "or" operators
            List<TypedValue> tvl =new List<TypedValue>(blkNames.Count + 2);
            // Add the initial operator
            tvl.Add(new TypedValue((int)DxfCode.Operator,"<or"));
            // Add an entry for each block name, prefixing the
            // anonymous block names with a reverse apostrophe
            foreach (var blkName in blkNames)
            {
                tvl.Add(new TypedValue((int)DxfCode.BlockName,(blkName.StartsWith("*") ? "`" + blkName : blkName)));
            }
            // Add the final operator
            tvl.Add(new TypedValue((int)DxfCode.Operator,"or>"));
            // Return an array from the list
            return tvl.ToArray();
        }
    }
}
